#include "qb_modules.h"
#include "qbmessage/include/message_kernel.h"
#include "qbnet/include/network_service.h"
#include "core/system/utf_util_win.h"
#include <core/QbLogger.h>

namespace qb
{
	ComItem QbModules::m_comDatabase[] = 
	{
		{_T("qbmessage.dll"),		CLSID_MessageKernel,	NULL},
		{_T("qbnet.dll"),			CLSID_NetworkService,	NULL},
	};

	QbModules::QbModules()
	{
	}

	QbModules::~QbModules()
	{
		assert(m_coms.size() == 0);
	}

	int32_t QbModules::LoadResource(const char* exepath)
	{
		return 0;
	}

	int32_t QbModules::UnloadResource()
	{
		if (m_coms.size() == 0)
		{
			log_warning("resource size is 0");
			return -1;
		}
		
        // 第一次遍历：释放那些未被其他对象包含的对象
        // 第二次遍历：释放那些未释放的对象, 并且卸载相应的模块
        // 之所以两次循环，是为了处理相互包含的情况
		for (Coms::iterator it = m_coms.begin(); it != m_coms.end(); ++it)
		{
			for (ComObjs::iterator it_obj = it->second.objs.begin(); it_obj != it->second.objs.end(); ++it_obj)
			{
				IUnknown* fac = static_cast<IUnknown*>(it_obj->second.ppv);
				if (fac)
				{
					int32_t uRef = fac->Release();
					if (uRef == 0)
                    {
                        // 对象已经完全释放
                        it_obj->second.ppv = NULL;
                    }
                    else
                    {
                        // 说明还在使用暂时还不能释放
                        fac->AddRef();
                    }
				}
                else
                {
                    assert(0);
                }
			}
		}
        for (Coms::iterator it = m_coms.begin(); it != m_coms.end(); ++it)
        {
            for (ComObjs::iterator it_obj = it->second.objs.begin(); it_obj != it->second.objs.end(); ++it_obj)
            {
                IUnknown* fac = static_cast<IUnknown*>(it_obj->second.ppv);
                if (fac)
                {
                    while(fac->Release() > 0);
                }
            }

            it->second.com->Unload();
        }

		m_coms.clear();

		return 0;
	}

	int32_t QbModules::QueryInterface(REFCLSID rclsid,REFIID riid,void** ppv)
	{
		Coms::iterator it_clsid = m_coms.find(rclsid);
		if (it_clsid == m_coms.end())
		{
			for (int32_t i = 0; i < kMaxNumberCom; i++)
			{
				if (rclsid == m_comDatabase[i].clsid)
				{
					QbCom* com = new QbCom();
					int32_t ret = com->Load(m_comDatabase[i].name.c_str());
					if (ret == 0)
					{
						ComItem item = m_comDatabase[i];
						item.com = com;
						m_coms[m_comDatabase[i].clsid] = item;
						it_clsid = m_coms.find(rclsid);
						break;
					}
					else
					{
						delete com;
					//	assert(0);
						return -1;
					}
				}
			}
		}

		if (it_clsid != m_coms.end())
		{
			ComObjs::iterator it_riid = it_clsid->second.objs.find(riid);
			if (it_riid == it_clsid->second.objs.end())
			{
				if (it_clsid->second.com->CreateInstance(rclsid,riid,ppv) == 0)
				{
					ComObjItem item;
					item.riid = riid;
					item.ppv = *ppv;
					((IUnknown*)item.ppv)->AddRef();
					it_clsid->second.objs[riid] = item;
					return 0;
				}
				else
				{
					assert(0);
				}
			}
			else if (SUCCEEDED(((IUnknown*)it_riid->second.ppv)->QueryInterface(riid,(void **)&*ppv)))
			{
				return 0;
			}
			else if (!it_riid->second.ppv)
			{
				assert(0);
			}
		}

		assert(0);
		return -1;		
	}

}  // namespace qb

